function TPeerInfo() {
    this.pId="";
    this.dId="";
    this.kId ="";
    this.srcKmsId ="";
    this.tag={};
}
function  TPeerType() {
    this.types =[
        {key:'send', factory: kurentoUtils.WebRtcPeer.WebRtcPeerSendonly},
        {key:'recv', factory: kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly},
        {key:'sendrecv', factory: kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv}
    ];
    this.index = 0 ;
    this.options ={
        configuration: {
            "iceServers": [
                {
                    urls: "stun:223.68.161.139:3478"
                },
                {
                    urls: ["turn:223.68.161.139:3478"],
                    username: "kurento",
                    credential: "kurento"
                }
            ]
        },
        mediaConstraints: {
            audio: true,
            video: {width: {exact: 1280}, height: {exact: 720}, frameRate: 10}
        }
    };
}
function TPeer() {
    this.owner ;
    this.info = new TPeerInfo();
    this.options = {
        peerType: new TPeerType() ,
        HD: 0 ,
        localVideo: null ,
        remoteVideo: null
    };
    this.kms = {
        peer: null ,
        end: null
    };
    this.open= function ( localVideo , remoteVideo , onOpen) {
        var me = this;
        try{
            me.options.remoteVideo = remoteVideo;
            me.options.localVideo = localVideo;
            me.close(function () {
                var createPeer = function (onCreatePeer) {
                    var opts = JSON.parse(JSON.stringify(me.options.peerType.options));
                    opts.localVideo = localVideo;
                    opts.remoteVideo = remoteVideo;
                    var factory = me.options.peerType.types[
                            me.options.peerType.index
                        ].factory;
                    var peer = factory(opts, function () {
                        me.owner.getDevices(function (deviceRes) {
                            peer.devices = deviceRes;
                            me.kms.peer = peer;
                            onCreatePeer(peer);
                        })
                    });
                };
                var createEnd = function (onCreateEnd) {
                    me.owner.pipe.create('WebRtcEndpoint', function (erEnd , end ) {
                        me.kms.end = end;
                        me.info.srcKmsId = me.info.kId;
                        me.info.kId = end.id;
                        if( me.options.HD>0){
                            me.owner.setHDWebRtcEndpoint(end, function () {
                                onCreateEnd(end);
                            })
                        }
                        else{
                            me.kms.end = end;
                            onCreateEnd(end);
                        }
                    })
                };
                createPeer(function (peer) {
                    createEnd(function (end) {
                        me.owner.bindPeerEnd(peer, end , function () {
                            me.owner.cb(onOpen);
                        })
                    })
                })
            });
        }
        catch (e) {
            console.log(e);
        }
    };
    this.close= function ( onClose  ) {
        var me = this;
        try{
            if( me.kms.peer &&  me.kms.peer!=null){
                me.kms.peer.peerConnection.close();
                me.kms.peer.dispose();
                me.kms.peer = null;
            }
            if( me.kms.end ){
                me.kms.end.release(function () {
                    try{
                        me.kms.end = null;
                        me.owner.cb(onClose);
                    }
                    catch (er) {
                        me.owner.cb(onClose);
                        console.log(er);
                    }
                })
            }
            else {
                me.owner.cb(onClose);
            }
        }
        catch (e) {
            console.log(e);
        }

    };
}
function TPeerMqClient() {
    this.config={
        clientId:"",
        host:"gmggf8g.mqtt.iot.bj.baidubce.com",
        port:443,
        uid:"gmggf8g/peer",
        pwd:"a52bwKg22dCAuQzB",
        autoSubscribTopics:[] ,
        byeMsg:{
            flag: 1 ,
            topic:"",
            msg:{
                ac:"acBye" ,
                clientId:""
            }
        }
    };
    this.owner = null;
    this.events={
        onConnect : function () {
            ;
        } ,
        onDisConnect : function (ev) {
            console.log(ev);
        } ,
        onRecMsg : function (topic , msgInfo) {
            ;
        }
    };
    this.client = null;
    this.getByeMsg = function () {
        var me  = this;
        var res = JSON.parse(JSON.stringify(me.config.byeMsg.msg));
        res.clientId = me.config.clientId
        return res;
    };
    this.open = function () {
        var me = this;
        try{
            var cId = me.config.clientId;
            if( (!cId) || (cId==null) || cId==""){
                cId = ["peerCid", (new Date()).getTime() , parseInt(1000*Math.random())].join('_');
                me.config.clientId = cId;
            }
            me.client = new Paho.Client(me.config.host, Number(me.config.port), cId);
            me.client.onConnected = function(ev){
                for( var i=0;i<me.config.autoSubscribTopics.length; i++){
                    var topic = me.config.autoSubscribTopics[i];
                    if( topic.indexOf("/#")<0){
                        topic =[topic , "#"].join('/');
                    }
                    me.client.subscribe(topic);

                }
                if( me.config.byeMsg.flag>0){
                    var byeTopic =[me.config.byeMsg.topic , "#"].join('/');
                    me.client.subscribe(byeTopic);

                }
                var handler = function () {
                    me.owner.cb( me.events.onConnect);
                }
                window.setTimeout(handler, 1500);
            };
            me.client.onConnectionLost = function(ev){
                me.owner.cb( me.events.onDisconnect , ev);
            };
            me.client.onMessageArrived = function(e){
                var aResult={
                    MsgContent : e.payloadString ,
                    Topic: e.topic,
                    Retain:e.retained,
                    Qos:e.qos
                };
                try {
                    var msgInfo ={};
                    try {
                        msgInfo = JSON.parse(aResult.MsgContent);
                    }
                    catch (eInfo) {
                        console.log(eInfo);
                    }
                    me.owner.cb(me.events.onRecMsg , aResult.Topic , msgInfo , aResult);
                }
                catch (eer) {
                    console.log(eer)
                }
            };

            var connectOptions = {
                invocationContext: {
                    host: me.config.host,
                    port: me.config.port,
                    path: "",
                    clientId: me.config.clientId
                },
                timeout: 10000,
                keepAliveInterval: 60,
                cleanSession: true,
                useSSL: window.location.href.toLowerCase().indexOf("https://")>=0,
                reconnect: true,
                userName :me.config.uid,
                password :me.config.pwd ,
                onSuccess: function(e){
                    //GateWay.Callback( GateWay.Events.OnConnected , GateWay);
                },
                onFailure:function(eDis){
                    me.cb(me.events.onDisconnect , eDis);
                }
            };
            if ( me.config.byeMsg.flag>0){
                var wmsgData = me.getByeMsg();
                var wmsg = new Paho.Message(JSON.stringify(wmsgData));
                wmsg.destinationName = me.config.byeMsg.topic;
                connectOptions.willMessage = wmsg;
            }

            me.client.connect(connectOptions);
        }
        catch (e) {
            console.log(e);
        }
    }
}
function TPeerControlers() {
    this.config={
        app:{
            appId:"hhRa" ,
            channelId:"",
            tag:{}
        },
        kurentUrl: "wss://wss.hhdata.cn:8433/kurento"
    };
    this.mqClient = new TPeerMqClient();
    this.pipe = null;
    this.kurentoClient  = null;
    this.masterPeer = new TPeer();
    this.peers = {};
    this.events = {
        onPeerChanged: function (flag , peer) {
            
        },
        onRecMsg: function (topic, msg) {
            
        }
    };
    this.getNewId= function (header) {
        var me = this;
        var res = "";
        try{
            res = [header , (new Date()).getTime().toString() , parseInt(1000*Math.random()).toString()].join('_');
        }
        catch (e) {
            console.log(e);
        }
        return res;
    };
    this.cb= function (callback, p0,p1,p2) {
        var me = this;
        try{
            if( callback){
                callback(p0,p1,p2);
            }
        }
        catch (e) {
            console.log(e);
        }
    };
    this.open= function ( localVideo , remoteVideo, onOpen) {
        var me = this;
        try{
            var openChannel = function (onOpenChannel) {
                me.getKmsClient(function (client) {
                    client.serverManager.getPipelines(function (erPs , ps) {
                        var index =0;
                        var getPipe= function () {
                            if( index < ps.length ){
                                var p = ps[index];
                                p.getName(function (erName, name) {
                                    if( name == me.config.app.channelId ){
                                        me.pipe = p;
                                        onOpenChannel(p);
                                    }
                                    else{
                                        index++;
                                        getPipe();
                                    }
                                });
                            }
                            else{
                                client.create("MediaPipeline", function (erNewPipe, np) {
                                    np.setName(me.config.app.channelId, function (erName) {
                                        me.pipe = np;
                                        onOpenChannel(np);
                                    })
                                })
                            }
                        }
                        getPipe();
                    })
                })
            };
            var openMasterPeer = function (onOpenMasterPeer) {
                var pId = me.getNewId( ['pId', me.config.app.appId , me.config.app.channelId ].join('_'));
                var hIdKey = [me.config.app.appId , 'hId'].join('-');
                var hId = window.localStorage.getItem(hIdKey);
                if( !hId){
                    hId = me.getNewId( ['hId', me.config.app.appId ].join('-'));
                    window.localStorage.setItem(hIdKey, hId);
                }
                me.masterPeer.owner = me;
                me.masterPeer.info.pId = pId;
                me.masterPeer.info.dId = hId;
                me.masterPeer.info.kId ="";
                me.masterPeer.options.HD = 1;

                me.masterPeer.options.peerType.index = 2;
                me.masterPeer.options.peerType.options.mediaConstraints.video.frameRate = 20;
                me.masterPeer.open(localVideo , remoteVideo,function () {
                    onOpenMasterPeer();
                });
            };
            var connectMqSvr = function () {
                me.mqClient.owner = this;
                var masterPeerInfoData =  me.masterPeer.info ;
                var channelTopic = ['channel', me.config.app.appId , me.config.app.channelId ].join('/');
                var peerTopic =  ['peer', me.config.app.appId , me.config.app.channelId, me.masterPeer.info.pId ].join('/');
                me.mqClient.config.clientId = me.masterPeer.info.pId;
                me.mqClient.config.autoSubscribTopics =[
                    channelTopic , peerTopic
                ];
                me.mqClient.config.byeMsg.flag = 1;
                me.mqClient.config.byeMsg.topic = channelTopic;
                me.mqClient.getByeMsg = function () {
                    var msg = {
                        ac:"acBye" ,
                        data: me.masterPeer.info ,
                        srcPeerId: me.masterPeer.info.pId
                    };
                    return msg;
                };
                me.mqClient.events.onConnect = function ( ) {
                    var content =JSON.stringify({
                        ac:"acHello" ,
                        srcPeerId: me.masterPeer.info.pId ,
                        data: masterPeerInfoData
                    });
                    me.mqClient.client.publish(channelTopic , content , 0 , false);
                };
                me.mqClient.events.onRecMsg = function (topic , msgInfo) {
                    if( msgInfo.ac){
                        if( msgInfo.ac == "acBye"){
                            me.removeRemotePeer(msgInfo.srcPeerId);
                        }
                        else if( msgInfo.ac == "acHello"){
                            var content =JSON.stringify({
                                ac:"acWelcome" ,
                                srcPeerId: me.masterPeer.info.pId ,
                                data: masterPeerInfoData
                            });
                            var recTopic = ['peer', me.config.app.appId , me.config.app.channelId, msgInfo.srcPeerId ].join('/');
                            me.mqClient.client.publish( recTopic , content , 0 , false);
                            if( msgInfo.srcPeerId != me.masterPeer.info.pId ){
                                me.newRemotePeer(msgInfo.data);
                            }
                        }
                        else if( msgInfo.ac == "acWelcome"){
                            me.newRemotePeer(msgInfo.data);
                        }
                        else {
                            me.cb(me.events.onRecMsg , topic , msgInfo);
                        }
                    }
                    else {
                        me.cb(me.events.onRecMsg , topic , msgInfo);
                    }
                };
                me.mqClient.open();
            };
            openChannel(function () {
                openMasterPeer(function () {
                    connectMqSvr();
                })
            })
        }
        catch (e) {
            console.log(e);
        }
    };
    this.connect= function (onConnect) {
        var me = this;
        try{
        }
        catch (e) {
            console.log(e);
        }
    };
    this.getKmsClient= function (callback) {
        var me = this;
        try{
            if( me.kurentoClient  && me.kurentoClient!=null){
                cb(callback,me.kurentoClient);
            }
            else{
                kurentoClient(me.config.kurentUrl, function (error, client) {
                    if (client) {
                        me.kurentoClient = client;
                        client.getServerManager(function (erSvr , svr) {
                            client.serverManager = svr;
                            me.cb(callback , client);
                        })
                    }
                });
            }
        }
        catch (e) {
            console.log(e);
        }
    };
    this.getDevices = function (onGet) {
        var me = this;
        try{
            var res ={};
            navigator.mediaDevices.enumerateDevices().then(function (devs) {
                try {
                    for (var i = 0; i < devs.length; i++) {
                        var item = devs[i];
                        if (!res[item.kind]) {
                            res[item.kind] = []
                        }
                        res[item.kind].push(item);
                    }
                }
                catch (er) {
                    console.log(er)
                }
                me.cb( onGet , res);
            }).catch(function () {
                me.cb( onGet , res);
            });
        }
        catch (e) {
            console.log(e);
        }
    };
    this.setHDWebRtcEndpoint = function ( end, onSet ) {
        var me = this;
        try{
            end.setMaxVideoRecvBandwidth(3000).then(()=>{
                return end.setMaxVideoRecvBandwidth(3000);
            }).then(()=>{
                return end.setMaxVideoSendBandwidth(3000);
            }).then(()=>{
                return end.setMinVideoRecvBandwidth(1500);
            }).then(()=>{
                return end.setMinVideoSendBandwidth(1500);
            }).then(()=>{
                me.cb( onSet)
            });
        }
        catch (e) {
            console.log(e);
        }
    };
    this.bindPeerEnd = function (peer , endpoint , callback) {
        var me = this;
        try{
            var setCandidateEvent = function (peer, endpoint) {
                try {
                    if (peer && endpoint) {
                        endpoint.on('OnIceCandidate', function (event) {
                            var candidate = event.candidate;
                            peer.addIceCandidate(candidate);
                            //console.log(candidate);
                            //console.log('candidate w->p')
                        });
                        peer.on('icecandidate', function (candidate) {
                            var iceCandidate = kurentoClient.register.complexTypes.IceCandidate(candidate);
                            endpoint.addIceCandidate(iceCandidate);
                            //console.log(iceCandidate,candidate);
                            //console.log('candidate p->w')

                        });
                    }
                } catch (e) {
                    ;
                }
            }
            if (endpoint && peer) {
                peer.generateOffer(function (errorPeerGenerateOffer, sdpOffer) {
                    if (errorPeerGenerateOffer && callback) {
                        callback(errorPeerGenerateOffer, null);
                    } else {
                        endpoint.processOffer(sdpOffer, function (errorSdpOffer, sdpAnswer) {
                            if (errorSdpOffer && callback) {
                                console.log("process sdpOffer error.", errorSdpOffer)
                                callback(errorSdpOffer, null);
                            } else {
                                setCandidateEvent(peer, endpoint);
                                peer.processAnswer(sdpAnswer);
                                endpoint.gatherCandidates(function (errorGatherCandidates) {
                                    if (errorGatherCandidates && callback) {
                                        console.log('webRtcPoint gatherCandidates error.', errorGatherCandidates)
                                        callback(errorGatherCandidates, null);
                                    } else {
                                        peer.endpoint = endpoint;
                                        endpoint.peer = peer;
                                        setCandidateEvent(peer, endpoint);
                                        if (callback) {
                                            callback(null, {endpoint: endpoint, peer: peer});
                                        }
                                    }
                                });
                            }
                        });
                    }
                });
            } else {
                if (callback) {
                    callback({error: "endPoint or peer is null."}, null);
                }
            }

        }
        catch (e) {
            console.log(e);
        }
    };
    this.newRemotePeer= function (remotePeerInfo  ) {
        var me = this;
        try{
            var np = new TPeer();
            np.owner = me ;
            np.info = remotePeerInfo;
            np.options.peerType.index=1;
            me.peers[np.info.pId] = np;
            me.cb(me.events.onPeerChanged , 1 , np);
        }
        catch (e) {
            console.log(e);
        }
    };
    this.removeRemotePeer= function (remotePeerId ,  callback) {
        var me = this;
        try{
            if( me.peers[remotePeerId] ){
                var p = me.peers[remotePeerId];
                p.close();
                delete me.peers[remotePeerId];
                me.cb(me.events.onPeerChanged , 0 , p);
            }
        }
        catch (e) {
            console.log(e);
        }
    };
}

var hhPeer = new TPeerControlers();